#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
智能农业大棚监控系统 - Flask后端服务器
接收STM32上传的传感器数据，提供Web管理界面
"""

from flask import Flask, render_template, jsonify, request
from flask_cors import CORS
import json
import time
import threading
from datetime import datetime
import logging

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

app = Flask(__name__)
CORS(app)  # 允许跨域访问

# 全局数据存储
greenhouse_data = {
    'nodes': {},  # 存储所有节点数据
    'system_status': {
        'total_nodes': 0,
        'online_nodes': 0,
        'last_update': None
    }
}

# 作物模板配置
crop_templates = {
    'tomato': {
        'name': '番茄',
        'soil_temp_min': 18,
        'soil_temp_max': 28,
        'soil_humidity_min': 60,
        'soil_humidity_max': 80,
        'co2_min': 400,
        'co2_max': 1000,
        'light_min': 20000,
        'light_max': 50000
    },
    'strawberry': {
        'name': '草莓',
        'soil_temp_min': 15,
        'soil_temp_max': 25,
        'soil_humidity_min': 70,
        'soil_humidity_max': 90,
        'co2_min': 350,
        'co2_max': 800,
        'light_min': 15000,
        'light_max': 40000
    },
    'general': {
        'name': '通用',
        'soil_temp_min': 16,
        'soil_temp_max': 30,
        'soil_humidity_min': 50,
        'soil_humidity_max': 85,
        'co2_min': 300,
        'co2_max': 1200,
        'light_min': 10000,
        'light_max': 60000
    }
}

# 节点超时时间 (秒)
NODE_TIMEOUT = 30

def check_node_status():
    """检查节点在线状态"""
    current_time = time.time()
    online_count = 0
    
    for node_id, node_data in greenhouse_data['nodes'].items():
        last_update = node_data.get('timestamp', 0)
        if current_time - last_update < NODE_TIMEOUT:
            node_data['status'] = 'online'
            online_count += 1
        else:
            node_data['status'] = 'offline'
    
    greenhouse_data['system_status']['online_nodes'] = online_count
    greenhouse_data['system_status']['last_update'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')

@app.route('/')
def index():
    """主页"""
    return render_template('index.html')

@app.route('/api/data', methods=['POST'])
def receive_data():
    """接收STM32上传的传感器数据"""
    try:
        data = request.get_json()
        
        if not data or 'node_id' not in data:
            return jsonify({'error': 'Invalid data format'}), 400
        
        node_id = str(data['node_id'])
        
        # 验证数据完整性
        required_fields = ['soil_temp', 'soil_humidity', 'co2', 'light', 'pump_status', 'heater_status']
        for field in required_fields:
            if field not in data:
                return jsonify({'error': f'Missing field: {field}'}), 400
        
        # 处理数据
        node_data = {
            'node_id': node_id,
            'soil_temp': float(data['soil_temp']),
            'soil_humidity': float(data['soil_humidity']),
            'co2': int(data['co2']),
            'light': int(data['light']),
            'pump_status': int(data['pump_status']),
            'heater_status': int(data['heater_status']),
            'timestamp': time.time(),
            'status': 'online'
        }
        
        # 存储数据
        greenhouse_data['nodes'][node_id] = node_data
        
        # 更新系统状态
        greenhouse_data['system_status']['total_nodes'] = len(greenhouse_data['nodes'])
        
        logger.info(f"收到节点 {node_id} 数据: 温度={node_data['soil_temp']}°C, 湿度={node_data['soil_humidity']}%, CO2={node_data['co2']}ppm, 光照={node_data['light']}lux")
        
        return jsonify({'status': 'success', 'message': 'Data received successfully'})
    
    except Exception as e:
        logger.error(f"接收数据错误: {str(e)}")
        return jsonify({'error': str(e)}), 500

@app.route('/api/data', methods=['GET'])
def get_data():
    """获取所有节点数据"""
    check_node_status()
    return jsonify(greenhouse_data)

@app.route('/api/nodes/<node_id>', methods=['GET'])
def get_node_data(node_id):
    """获取指定节点数据"""
    check_node_status()
    
    if node_id not in greenhouse_data['nodes']:
        return jsonify({'error': 'Node not found'}), 404
    
    return jsonify(greenhouse_data['nodes'][node_id])

@app.route('/api/control/<node_id>', methods=['POST'])
def control_device(node_id):
    """控制设备开关"""
    try:
        data = request.get_json()
        
        if not data:
            return jsonify({'error': 'No control data provided'}), 400
        
        # 验证节点是否存在
        if node_id not in greenhouse_data['nodes']:
            return jsonify({'error': 'Node not found'}), 404
        
        # 构建控制命令
        control_cmd = {
            'node_id': node_id,
            'command': 'manual_control'
        }
        
        if 'pump_status' in data:
            control_cmd['pump_status'] = int(data['pump_status'])
        
        if 'heater_status' in data:
            control_cmd['heater_status'] = int(data['heater_status'])
        
        # 这里应该将命令发送回STM32
        # 由于STM32是客户端，我们需要等待下次数据上传时携带命令
        # 简化处理：直接存储控制状态
        if 'pump_status' in control_cmd:
            greenhouse_data['nodes'][node_id]['manual_pump'] = control_cmd['pump_status']
        
        if 'heater_status' in control_cmd:
            greenhouse_data['nodes'][node_id]['manual_heater'] = control_cmd['heater_status']
        
        logger.info(f"节点 {node_id} 控制命令: {control_cmd}")
        
        return jsonify({'status': 'success', 'command': control_cmd})
    
    except Exception as e:
        logger.error(f"控制设备错误: {str(e)}")
        return jsonify({'error': str(e)}), 500

@app.route('/api/templates', methods=['GET'])
def get_templates():
    """获取作物模板"""
    return jsonify(crop_templates)

@app.route('/api/templates/<template_name>', methods=['POST'])
def apply_template(template_name):
    """应用作物模板"""
    try:
        if template_name not in crop_templates:
            return jsonify({'error': 'Template not found'}), 404
        
        data = request.get_json()
        node_id = str(data.get('node_id', '1'))
        
        template = crop_templates[template_name]
        
        # 构建模板应用命令
        template_cmd = {
            'node_id': node_id,
            'command': 'apply_template',
            'template': template_name,
            'thresholds': {
                'soil_temp_min': template['soil_temp_min'],
                'soil_temp_max': template['soil_temp_max'],
                'soil_humidity_min': template['soil_humidity_min'],
                'soil_humidity_max': template['soil_humidity_max'],
                'co2_min': template['co2_min'],
                'co2_max': template['co2_max'],
                'light_min': template['light_min'],
                'light_max': template['light_max']
            }
        }
        
        logger.info(f"节点 {node_id} 应用模板: {template['name']}")
        
        return jsonify({'status': 'success', 'template': template, 'command': template_cmd})
    
    except Exception as e:
        logger.error(f"应用模板错误: {str(e)}")
        return jsonify({'error': str(e)}), 500

@app.route('/api/alarm/<node_id>', methods=['POST'])
def handle_alarm(node_id):
    """处理报警"""
    try:
        data = request.get_json()
        alarm_type = data.get('type', 'unknown')
        message = data.get('message', '')
        
        logger.warning(f"节点 {node_id} 报警: {alarm_type} - {message}")
        
        # 这里可以添加邮件、短信等通知功能
        # 简化处理：只记录日志
        
        return jsonify({'status': 'success', 'message': 'Alarm handled'})
    
    except Exception as e:
        logger.error(f"处理报警错误: {str(e)}")
        return jsonify({'error': str(e)}), 500

def background_task():
    """后台任务：清理过期数据"""
    while True:
        try:
            current_time = time.time()
            
            # 清理过期节点数据
            expired_nodes = []
            for node_id, node_data in greenhouse_data['nodes'].items():
                if current_time - node_data.get('timestamp', 0) > NODE_TIMEOUT * 2:
                    expired_nodes.append(node_id)
            
            for node_id in expired_nodes:
                del greenhouse_data['nodes'][node_id]
                logger.info(f"清理过期节点: {node_id}")
            
            # 更新系统状态
            greenhouse_data['system_status']['total_nodes'] = len(greenhouse_data['nodes'])
            
            time.sleep(60)  # 每分钟检查一次
            
        except Exception as e:
            logger.error(f"后台任务错误: {str(e)}")
            time.sleep(60)

if __name__ == '__main__':
    # 启动后台任务
    bg_thread = threading.Thread(target=background_task, daemon=True)
    bg_thread.start()
    
    logger.info("智能农业大棚监控系统服务器启动")
    logger.info("访问地址: http://localhost:5000")
    
    # 启动Flask应用
    app.run(host='0.0.0.0', port=5000, debug=True, threaded=True)
